home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / tde11.arc / BLOCK.C next >
C/C++ Source or Header  |  1991-09-06  |  49KB  |  1,419 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - block commands module
  10.  * Purpose: This file contains all the commands than manipulate blocks.
  11.  * File:    block.c
  12.  * Author:  Douglas Thomson
  13.  * System:  this file is intended to be system-independent
  14.  * Date:    October 1, 1989
  15.  */
  16. /*********************  end of original comments   ********************/
  17.  
  18. /*
  19.  * The block routines have been EXTENSIVELY rewritten.  I am not very fond of
  20.  * stream blocks.  This editor uses LINE blocks and BOX blocks.  That is,
  21.  * one may either mark entire lines or column blocks.  Block operations are
  22.  * done in place.  There are no paste and cut buffers.  In limited memory
  23.  * situations, larger block operations can be carried out.  Block operations
  24.  * can be done within or across files.  One disadvantage of not using buffers
  25.  * is that block operations can be slow.  The most complicated routine in
  26.  * this editor is by far "move_copy_delete_overlay_block( window, action )".
  27.  * I put some comments in, but it can be hard to understand.
  28.  *
  29.  * Maybe in the next version I'll use buffers to speed up block operations.
  30.  *
  31.  * In tde, version 1.1, I separated the BOX and LINE actions.  LINE actions
  32.  * are a LOT faster, now.  Still need to speed up BOX actions.
  33.  *
  34.  * New editor name:  tde, the Thomson-Davis Editor.
  35.  * Author:           Frank Davis
  36.  * Date:             June 5, 1991
  37.  *
  38.  * This modification of Douglas Thomson's code is released into the
  39.  * public domain, Frank Davis.  You may distribute it freely.
  40.  */
  41.  
  42. #include "tdestr.h"
  43. #include "common.h"
  44. #include "tdefunc.h"
  45. #include "define.h"
  46.  
  47.  
  48. /*
  49.  * Name:    mark_block
  50.  * Purpose: To record the position of the start of the block in the file.
  51.  * Date:    June 5, 1991
  52.  * Passed:  window: information required to access current window
  53.  *          type: type of block LINE or BOX
  54.  * Notes:   Assume the user will mark begin and end of a block in either
  55.  *           line mode or box mode.  If the user mixes type, then block
  56.  *           type defaults to LINE.
  57.  */
  58. void mark_block( window, type )
  59. windows *window;
  60. int type;
  61. {
  62. file_infos *file;     /* temporary file variable */
  63. int num;
  64. long lnum;
  65.  
  66.    if (g_status.marked == FALSE) {
  67.       g_status.marked = TRUE;
  68.       g_status.marked_file = window->file_info;
  69.    }
  70.    file = window->file_info;
  71.    g_status.marked_window = window;
  72.  
  73.    /*
  74.     * define blocks for only one file.  it is ok to modify blocks in any window
  75.     * pointing to original marked file.
  76.     */
  77.    if (file == g_status.marked_file) {
  78.  
  79.       /*
  80.        * mark beginning and ending column regardless of block mode.
  81.        */
  82.       if (file->block_type == NOTMARKED) {
  83.          file->block_ec  = file->block_bc = window->rcol;
  84.          file->block_er  = file->block_br = window->rline;
  85.       } else {
  86.          if (file->block_br > window->rline) {
  87.             file->block_br = window->rline;
  88.             if (file->block_bc < window->rcol)
  89.                file->block_ec = window->rcol;
  90.             else
  91.                file->block_bc = window->rcol;
  92.          } else {
  93.             file->block_ec = window->rcol;
  94.             file->block_er = window->rline;
  95.          }
  96.  
  97.          /*
  98.           * if user marks ending line less than beginning line then switch
  99.           */
  100.          if (file->block_er < file->block_br) {
  101.             lnum = file->block_er;
  102.             file->block_er = file->block_br;
  103.             file->block_br = lnum;
  104.          }
  105.  
  106.          /*
  107.           * if user marks ending column less than beginning column then switch
  108.           */
  109.          if (file->block_ec < file->block_bc) {
  110.             num = file->block_ec;
  111.             file->block_ec = file->block_bc;
  112.             file->block_bc = num;
  113.          }
  114.       }
  115.  
  116.       /*
  117.        * block type in now defined.  if user mixes block type then default to
  118.        * LINE block.
  119.        */
  120.       if (file->block_type == NOTMARKED)
  121.          file->block_type = type;
  122.       else if (file->block_type == BOX && type == LINE)
  123.          file->block_type = LINE;
  124.       file->dirty = GLOBAL;
  125.       redraw_screen( window );
  126.    }
  127. }
  128.  
  129. /*
  130.  * Name:    unmark_block
  131.  * Purpose: To set all block information to NULL or 0
  132.  * Date:    June 5, 1991
  133.  * Notes:   Reset all block variables if marked, otherwise return.
  134.  *           If a block is unmarked then redraw the screen(s).
  135.  */
  136. void unmark_block( )
  137. {
  138. file_infos *marked_file;
  139. windows *window;
  140.  
  141.    if (g_status.marked == TRUE) {
  142.       window = g_status.marked_window;
  143.       marked_file              = g_status.marked_file;
  144.       g_status.marked          = FALSE;
  145.       g_status.marked_file     = NULL;
  146.       g_status.marked_window   = NULL;
  147.       marked_file->block_start = NULL;
  148.       marked_file->block_end   = NULL;
  149.       marked_file->block_bc    = marked_file->block_ec = 0;
  150.       marked_file->block_br    = marked_file->block_er = 0l;
  151.       if (marked_file->block_type) {
  152.          marked_file->dirty = GLOBAL;
  153.          redraw_screen( window );
  154.       }
  155.       marked_file->block_type  = NOTMARKED;
  156.    }
  157. }
  158.  
  159. /*
  160.  * Name:    restore_marked_block
  161.  * Purpose: To restore block beginning and ending row after an editing function
  162.  * Date:    June 5, 1991
  163.  * Passed:  window: information required to access current window
  164.  *          net_change: number of bytes added or subtracted
  165.  * Notes:   If a change has been made before the marked block then the
  166.  *           beginning and ending row need to be adjusted by the number of
  167.  *           lines added or subtracted from file.
  168.  */
  169. void restore_marked_block( window, net_change )
  170. windows *window;
  171. int net_change;
  172. {
  173. file_infos *marked_file;
  174. long length;
  175.  
  176.    if (g_status.marked == TRUE && net_change != 0) {
  177.       marked_file = g_status.marked_file;
  178.       length = marked_file->length;
  179.  
  180.       /*
  181.        * restore is needed only if a block is defined and window->file_info is
  182.        * same as marked file and there was a net change in file length.
  183.        */
  184.       if (marked_file == window->file_info) {
  185.  
  186.          /*
  187.           * if cursor is before marked block then adjust block by net change.
  188.           */
  189.          if (marked_file->block_br > window->rline) {
  190.             marked_file->block_br += net_change;
  191.             marked_file->block_er += net_change;
  192.             marked_file->dirty = GLOBAL;
  193.          /*
  194.           * if cursor is somewhere in marked block don't restore, do redisplay
  195.           */
  196.          } else if (marked_file->block_er >= window->rline)
  197.             marked_file->dirty = GLOBAL;
  198.  
  199.          /*
  200.           * check for lines of marked block beyond end of file
  201.           */
  202.          if (marked_file->block_br > length)
  203.             unmark_block( );
  204.          else if (marked_file->block_er > length) {
  205.             marked_file->block_er = length;
  206.             marked_file->dirty = GLOBAL;
  207.          }
  208.       }
  209.    }
  210. }
  211.  
  212. /*
  213.  * Name:    prepare_block
  214.  * Purpose: To prepare a window/file for a block read, move or copy.
  215.  * Date:    June 5, 1991
  216.  * Passed:  window: current window
  217.  *          file: pointer to file information.
  218.  *          text_line: pointer to line in file to prepare.
  219.  *          lend: line length.
  220.  *          bc: beginning column of BOX.
  221.  * Notes:   The main complication is that the cursor may be beyond the end
  222.  *           of the current line, in which case extra padding spaces have
  223.  *           to be added before the block operation can take place.
  224.  *           This only occurs in BOX operations.
  225.  */
  226. int  prepare_block( window, text_line, lend, bc )
  227. windows *window;
  228. text_ptr text_line;
  229. int lend, bc;
  230. {
  231. text_ptr source;        /* source for block moves */
  232. text_ptr dest;          /* destination for block moves */
  233. file_infos *file;       /* temp file pointer */
  234. int pad, i;             /* amount of padding to be added */
  235. int number;             /* number of characters for block moves */
  236. int prompt_line;
  237.  
  238.    prompt_line = window->bottom_line;
  239.    file = window->file_info;
  240.    copy_line( text_line, prompt_line );
  241.  
  242.    /*
  243.     * work out how much padding is required to extend the current
  244.     *  line to the cursor position
  245.     */
  246.  
  247.    pad = bc - lend;
  248.  
  249.    /*
  250.     * make room for the padding spaces
  251.     */
  252.    source = g_status.line_buff + lend;
  253.    dest = source + pad;
  254.    number = pad + 2;
  255.    memmove( dest, source, number );
  256.  
  257.    /*
  258.     * insert the padding spaces
  259.     */
  260.    for (i=pad; i>0; i--)
  261.       *source++ = ' ';
  262.    un_copy_line( text_line, window, FALSE );
  263.    return( pad );
  264. }
  265.  
  266.  
  267. /*
  268.  * Name:    pad_dest_line
  269.  * Purpose: To prepare a window/file for a block move or copy.
  270.  * Date:    June 5, 1991
  271.  * Passed:  window: current window
  272.  *          dest_file: pointer to file information.
  273.  *          dest_line: pointer to line in file to prepare.
  274.  * Notes:   We are doing a BOX action (except DELETE).   We have come to the
  275.  *          end of the file and have no more lines.  All this routine does
  276.  *          is add a blank line to file.
  277.  */
  278. void pad_dest_line( window, dest_file, dest_line )
  279. windows *window;
  280. file_infos *dest_file;
  281. text_ptr dest_line;
  282. {
  283.    /*
  284.     * put linefeed in line_buff. dest_line should be pointing to
  285.     * file->end_text - 1.  since we inserted line feed, increment file length.
  286.     */
  287.    g_status.line_buff[0] = '\n';
  288.    g_status.line_buff[1] = CONTROL_Z;
  289.    g_status.copied = TRUE;
  290.    un_copy_line( dest_line, window, FALSE );
  291.    ++dest_file->length;
  292. }
  293.  
  294.  
  295. /*
  296.  * Name:    move_copy_delete_overlay_block
  297.  * Purpose: Master BOX or LINE routine.
  298.  * Date:    June 5, 1991
  299.  * Passed:  window: information required to access current window
  300.  *          action: action to take on a marked block
  301.  * Notes:   Operations on BOXs or LINES require several common operations.
  302.  *           All require finding the beginning and ending marks.  The
  303.  *           big differences are whether to delete the source block, copy the
  304.  *           source block, or leave the source block marked.
  305.  *          This routine will handle block operations across files.  Since one
  306.  *           must determine the relationship of source and destination blocks
  307.  *           within a file, it is relatively easy to expand this relationship
  308.  *           across files.  There are several caveats.  Most deal with the
  309.  *           difference between LINE and BOX operations others deal with
  310.  *           differences between operations within a file and operations
  311.  *           across files.
  312.  *          This is probably the most complicated routine in the editor.  It
  313.  *           is not easy to understand.
  314.  */
  315. void move_copy_delete_overlay_block( window, action )
  316. windows *window;
  317. int action;
  318. {
  319. windows *source_window; /* source window for block moves */
  320. text_ptr source;        /* source for block moves */
  321. text_ptr dest;          /* destination for block moves */
  322. text_ptr p;             /* temporary text pointer */
  323. long number;            /* number of characters for block moves */
  324. int lens;               /* length of source line */
  325. int lend;               /* length of destination line */
  326. int add;                /* characters being added from another line */
  327. int block_len;          /* length of the block */
  328. text_ptr block_start;   /* start of block in file */
  329. text_ptr block_end;     /* end of block in file - not same for LINE or BOX */
  330. char block_buff[BUFF_SIZE+2];
  331. int prompt_line;
  332. int same;               /* are these files the same */
  333. int source_first;       /* is source file lower in memory than dest */
  334. file_infos *source_file, *dest_file;
  335. int rcol, bc, ec;       /* temporary column variables */
  336. int xbc, xec;           /* temporary column variables */
  337. long rline;             /* temporary real line variable */
  338. long br, er, li;        /* temporary line variables */
  339. long dest_add;          /* number of bytes added to destination file */
  340. long source_sub;        /* number of bytes sub from source file */
  341. long diff;
  342. unsigned long block_size;
  343. int block_type;
  344. int fill_char;
  345. int fill_pad;           /* number of padding required for FILL or OVERLAY */
  346. windows s_w, d_w;       /* a couple of temporary windows for BOX stuff */
  347.  
  348.    /*
  349.     * initialize block variables
  350.     */
  351.    un_copy_line( window->cursor, window, TRUE );
  352.    source_window = g_status.marked_window;
  353.    prompt_line = window->bottom_line;
  354.    dest_file = window->file_info;
  355.    source_file = g_status.marked_file;
  356.    check_block( );
  357.    if (g_status.marked == FALSE)
  358.       return;
  359.    block_start = source_file->block_start;
  360.    block_end = source_file->block_end;
  361.    block_type = source_file->block_type;
  362.    dest = window->cursor = cpf( window->cursor );
  363.    rline = window->rline;
  364.  
  365.    /*
  366.     * if this is a LINE action, put the text below the current line
  367.     */
  368.    if (block_type == LINE && action != DELETE)
  369.       if ((p = find_next( dest )) != NULL)
  370.          dest = p;
  371.    /*
  372.     * must find out if source and destination file are the same.
  373.     * it don't matter with FILL and DELETE - those actions only modify the
  374.     * source file.
  375.     */
  376.    same = FALSE;
  377.    if (action == FILL) {
  378.       if (block_type == BOX) {
  379.          if (get_block_fill_char( window, &fill_char ) == ERROR)
  380.             return;
  381.          dest = block_start;
  382.          same = TRUE;
  383.       } else {
  384.          error( WARNING, prompt_line, "can only fill box blocks" );
  385.          return;
  386.       }
  387.    }
  388.    if (source_file == dest_file && action != DELETE && action != FILL) {
  389.       same = TRUE;
  390.       if (block_type == BOX && action == MOVE) {
  391.          if (rline == dest_file->block_br  &&
  392.               (window->rcol >= dest_file->block_bc &&
  393.                window->rcol <= dest_file->block_ec))
  394.              /*
  395.               * a block moved to within the block itself has no effect
  396.               */
  397.             return;
  398.       } else if (block_type == LINE) {
  399.          if (rline >= dest_file->block_br && rline <= dest_file->block_er) {
  400.              /*
  401.               * if COPYing or KOPYing within the block itself, reposition the
  402.               * destination to the next line after the block (if it exists)
  403.               */
  404.             if (action == COPY || action == KOPY)
  405.                dest = cpf( block_end );
  406.              /*
  407.               * a block moved to within the block itself has no effect
  408.               */
  409.             else if (action == MOVE)
  410.                return;
  411.          }
  412.       }
  413.    }
  414.  
  415.    /*
  416.     * set up Beginning Column, Ending Column, Beginning Row, Ending Row
  417.     */
  418.    bc = source_file->block_bc;
  419.    ec = source_file->block_ec;
  420.    br = source_file->block_br;
  421.    er = source_file->block_er;
  422.  
  423.    /*
  424.     * if we are BOX FILLing, beginning column is bc, not the column of cursor
  425.     */
  426.    if (action == FILL)
  427.      rcol = bc;
  428.    else
  429.       rcol = window->rcol;
  430.    dest_add = source_sub = 0;
  431.  
  432.    /*
  433.     * must know if source of block is before or after destination
  434.     */
  435.    source_first = FALSE;
  436.    if (ptoul( dest ) > ptoul( source_file->block_start ))
  437.       source_first = TRUE;
  438.    if (same && block_type == BOX) {
  439.       if ( rline >= br)
  440.          source_first = TRUE;
  441.    }
  442.  
  443.    /*
  444.     * work out how much has to be moved
  445.     */
  446.    if (block_type == BOX) {
  447.       block_size = ((ec+1) - bc) * ((er+1) - br);
  448.       if (action != DELETE)
  449.          block_size += ((rcol+1) * ((er+1) - br));
  450.       else
  451.          block_size = 0;
  452.    } else if (block_type == LINE) {
  453.       if (action == COPY || action == KOPY)
  454.          block_size = ptoul( block_end ) - ptoul( block_start );
  455.       else
  456.          block_size = 0;
  457.    } else
  458.       return;
  459.  
  460.    /*
  461.     * check that there is room to add block to file
  462.     */
  463.    if (ptoul( g_status.end_mem ) + block_size >= ptoul( g_status.max_mem )) {
  464.       error( WARNING, prompt_line, "not enough memory for block" );
  465.       return;
  466.    }
  467.  
  468.    /*
  469.     * 1. can't create lines greater than g_display.line_length
  470.     * 2. if we are FILLing a BOX - fill block buff once right here
  471.     * 3. only allow overlaying BOXs
  472.     */
  473.    if (block_type == BOX) {
  474.       block_len = (ec+1) - bc;
  475.       if (action != DELETE && action != FILL) {
  476.          if (rcol + block_len > g_display.line_length) {
  477.             error( WARNING, prompt_line, "line would be too long" );
  478.             return;
  479.          }
  480.       } else if (action == FILL)
  481.          block_fill( block_buff, fill_char, block_len );
  482.    } else {
  483.       block_len = 0;
  484.       if (action == OVERLAY) {
  485.          error( WARNING, prompt_line, "can only overlay blocks" );
  486.          return;
  487.       }
  488.    }
  489.  
  490.    /*
  491.     * all block actions go forward thru file - check those pointers
  492.     */
  493.    source = cpf( block_start );
  494.    dest = cpf( dest );
  495.    if (block_type == LINE) {
  496.       diff = ptoul( block_end ) - ptoul( block_start );
  497.       dest_add = source_sub = diff;
  498.       if (action != DELETE) {
  499.          p = addltop( diff, dest );
  500.          number = ptoul( g_status.end_mem ) - ptoul( dest );
  501.          hw_move( p, dest, number );
  502.          g_status.end_mem = addltop( diff, g_status.end_mem);
  503.       }
  504.       if (action != DELETE && !source_first)
  505.          source = addltop( diff, source );
  506.       if (action == COPY || action == KOPY || action == MOVE)
  507.          hw_move( dest, source, diff );
  508.       if (action == DELETE || action == MOVE) {
  509.          p = addltop( diff, source );
  510.          number = ptoul( g_status.end_mem ) - ptoul( p );
  511.          hw_move( source, p, number );
  512.          g_status.end_mem = addltop( -diff, g_status.end_mem);
  513.       }
  514.       if (action == DELETE)
  515.          dest_add = 0;
  516.       else if (action == COPY || action == KOPY)
  517.          source_sub = 0;
  518.       diff = (er+1l) - br;
  519.       if (action == COPY || action == KOPY || action == MOVE)
  520.          dest_file->length += diff;
  521.       if (action == DELETE || action == MOVE)
  522.          source_file->length -= diff;
  523.       if (action == DELETE && source_window->rline >= br) {
  524.          source_window->rline -= ((er + 1) - br);
  525.          if (source_window->rline < br)
  526.             source_window->rline = br;
  527.       }
  528.       /*
  529.        * the block action is now complete.  restore all the start_text and
  530.        * end_text pointers for all open files.
  531.        */
  532.       if (action == MOVE || action == DELETE)
  533.          restore_start_end( dest_file, source_file, dest_add, -source_sub,
  534.                             source_first );
  535.       else
  536.          restore_start_end( dest_file, source_file, dest_add, source_sub,
  537.                             source_first );
  538.       /*
  539.        * restore all cursors in all windows
  540.        */
  541.       restore_cursors( dest_file, source_file );
  542.    } else {
  543.       dup_window_info( &s_w, source_window );
  544.       dup_window_info( &d_w, window );
  545.       s_w.rline = br;
  546.       for (li=br; li<=er; li++, s_w.rline++, d_w.rline++) {
  547.          lens = linelen( source );
  548.          lend = linelen( dest );
  549.  
  550.          /*
  551.           * if we are doing a BOX action and both the source and
  552.           * destination are 0 then we have nothing to do.  all LINE actions
  553.           * require processing.
  554.           */
  555.          if (lens != 0 || lend != 0) {
  556.  
  557.             /*
  558.              * do actions that may require adding to file
  559.              */
  560.             if (action==MOVE || action==COPY || action==KOPY || action==FILL ||
  561.                 action == OVERLAY) {
  562.                d_w.cursor = dest;
  563.                if (action != FILL) {
  564.                   xbc = bc;
  565.                   xec = ec;
  566.                   if (action != OVERLAY  && block_type == BOX && same) {
  567.                      if (rcol < bc && rline > br && rline <=er)
  568.                         if (li >= rline) {
  569.                            xbc = bc + block_len;
  570.                            xec = ec + block_len;
  571.                         }
  572.                   }
  573.                   load_buff( block_buff, source, xbc, xec, block_type );
  574.                }
  575.                add = 0;
  576.                if (lend < (rcol+1))
  577.                   add = prepare_block( &d_w, dest, lend, rcol );
  578.                add += copy_buff_2file( &d_w, block_buff, dest, rcol,
  579.                                 block_len, action );
  580.                if (!source_first)
  581.                   source += add;
  582.             }
  583.  
  584.             /*
  585.              * do actions that may require deleting from file
  586.              */
  587.             if (action == MOVE || action == DELETE) {
  588.                s_w.cursor = source;
  589.                if (lens >= (bc + 1)) {
  590.                   add = block_len;
  591.                   xbc = bc;
  592.                   if (lens <= (ec + 1))
  593.                      add = lens - bc;
  594.                   if (same && action == MOVE) {
  595.                      if (rcol < bc && rline >= br && rline <=er)
  596.                         if (li >= rline)
  597.                            xbc = bc + block_len;
  598.                   }
  599.                   delete_blocked_block( &s_w, source, xbc, add,
  600.                                         prompt_line );
  601.                }
  602.             }
  603.          }
  604.  
  605.          /*
  606.           * if we are doing any BOX action we need to move the source pointer
  607.           * to the next line.
  608.           */
  609.          source = find_next( source );
  610.  
  611.          /*
  612.           * if we are doing any action other than DELETE, we need to move
  613.           * the destination to the next line in marked block.
  614.           * In BOX mode, we may need to pad the end of the file
  615.           * with a blank line before we process the next line.
  616.           */
  617.          if (action != DELETE) {
  618.             p = find_next( dest );
  619.             if (p != NULL)
  620.                dest = p;
  621.             else {
  622.                diff = 0l;
  623.                if (source_first || same) {
  624.                   if (action == MOVE)
  625.                      diff = dest_add - source_sub;
  626.                   else
  627.                      diff = dest_add + source_sub;
  628.                } else
  629.                   diff = dest_add;
  630.                p = addltop( -1, dest_file->end_text);
  631.                pad_dest_line( window, dest_file, p );
  632.                dest = find_next( dest );
  633.             }
  634.          }
  635.       }
  636.    }
  637.  
  638.    dest_file->modified = TRUE;
  639.    dest_file->dirty = GLOBAL;
  640.    if (action == MOVE  ||  action == DELETE || action == FILL) {
  641.       source_file->modified = TRUE;
  642.       source_file->dirty = GLOBAL;
  643.    }
  644.  
  645.    /*
  646.     * unless we are doing a KOPY, FILL, or OVERLAY we need to unmark the
  647.     * block.  if we just did a KOPY, the beginning and ending may have
  648.     * changed.  so, we must readjust beginning and ending rows.
  649.     */
  650.    if (action == KOPY) {
  651.       if (same && !source_first && block_type == LINE) {
  652.          number = (er+1) - br;
  653.          source_file->block_br += number;
  654.          source_file->block_er += number;
  655.       } else if (same && !source_first && window->rline == br &&
  656.                  block_type == BOX) {
  657.          add = (ec+1) - bc;
  658.          source_file->block_bc += add;
  659.          source_file->block_ec += add;
  660.       }
  661.       redraw_screen( window );
  662.    } else if (action != FILL && action != OVERLAY)
  663.       unmark_block( );
  664.    show_avail_mem( );
  665. }
  666.  
  667.  
  668. /*
  669.  * Name:    load_buff
  670.  * Purpose: copy the contents of a line in a BOX to the block buffer.
  671.  * Date:    June 5, 1991
  672.  * Passed:  block_buff: local buffer for block moves
  673.  *          source:  source line in file
  674.  *          bc:  beginning column of BOX. used only in BOX operations.
  675.  *          ec:  ending column of BOX. used only in BOX operations.
  676.  *          block_type:  LINE or BOX
  677.  * Notes:   If the block is marked in LINE mode, copy the line to the
  678.  *          block buffer.  If the block is marked in BOX mode, there are
  679.  *          several things to take care of.   1) The BOX begins and ends
  680.  *          within a line - just copy the blocked characters to the block buff.
  681.  *          2) the BOX begins within a line but ends past the eol - copy
  682.  *          all the characters within the line to the block buff then fill with
  683.  *          padding.  3) the BOX begins and ends past eol - fill entire
  684.  *          block buff with padding.
  685.  */
  686. void load_buff( block_buff, source, bc, ec, block_type )
  687. char *block_buff;
  688. text_ptr source;
  689. int bc, ec, block_type;
  690. {
  691. int len, pad, avlen, i;
  692.  
  693.    len = linelen( source );
  694.    if (block_type == LINE) {
  695.       if (source[len] == '\n')
  696.          ++len;
  697.       for (i=len; i>0; i++)
  698.          *block_buff++ = *source++;
  699.    } else {
  700.       /*
  701.        * block start may be past eol
  702.        */
  703.       if (len < ec + 1) {
  704.          /*
  705.           * does block start past eol? - fill with pad
  706.           */
  707.          if (len < bc) {
  708.             pad = (ec + 1) - bc;
  709.             for (i=pad; i>0; i--)
  710.                *block_buff++ = ' ';
  711.          } else {
  712.             /*
  713.              * block ends past eol - fill with pad
  714.              */
  715.             pad = (ec + 1) - len;
  716.             avlen = len - bc;
  717.             source = source + bc;
  718.             for (i=avlen; i>0; i--)
  719.                *block_buff++ = *source++;
  720.             for (i=pad; i>0; i--)
  721.                *block_buff++ = ' ';
  722.          }
  723.       } else {
  724.          /*
  725.           * block is within line - copy block to buffer
  726.           */
  727.          avlen = (ec + 1) - bc;
  728.          source = source + bc;
  729.          for (i=avlen; i>0; i--)
  730.             *block_buff++ = *source++;
  731.       }
  732.    }
  733.    *block_buff++ = CONTROL_Z;
  734.    *block_buff = '\0';
  735. }
  736.  
  737.  
  738. /*
  739.  * Name:    copy_buff_2file
  740.  * Purpose: copy the contents of block buffer to destination file
  741.  * Date:    June 5, 1991
  742.  * Passed:  window:  current window
  743.  *          block_buff:  local buffer for moves
  744.  *          dest:  pointer to destination line in destination file
  745.  *          rcol:  if in BOX mode, destination column in destination file
  746.  *          block_len:  if in BOX mode, width of block to copy
  747.  *          action:  type of block action
  748.  * Notes:   In BOX mode, the destination line has already been prepared.
  749.  *          Just copy the BOX buffer to the destination line.
  750.  */
  751. int  copy_buff_2file( window, block_buff, dest, rcol, block_len, action )
  752. windows *window;
  753. char *block_buff;
  754. text_ptr dest;
  755. int rcol, block_len, action;
  756. {
  757. text_ptr s;
  758. text_ptr d;
  759. long number;
  760. int i;
  761. int prompt_line;
  762. int rc;
  763.  
  764.    rc = 0;
  765.    prompt_line = window->bottom_line;
  766.    copy_line( dest, prompt_line );
  767.    s = g_status.line_buff + rcol;
  768.  
  769.    /*
  770.     * s is pointing to location to perform BOX operation.  If we do a
  771.     * FILL or OVERLAY, we do not necessarily add any extra space.  If the
  772.     * line does not extend all the thru the BOX then we add.
  773.     * we always add space when we COPY, KOPY, or MOVE
  774.     */
  775.    if (action == FILL || action == OVERLAY) {
  776.       i = linelen( s );
  777.       if (i < block_len) {
  778.          rc = block_len - i;
  779.          d = s + rc;
  780.          i = block_len + 1 + linelen( g_status.line_buff ) - rcol;
  781.          memmove( d, s, i );
  782.       }
  783.    } else {
  784.       rc = block_len;
  785.       d = s + block_len;
  786.       i = block_len + 1 + linelen( g_status.line_buff ) - rcol;
  787.       memmove( d, s, i );
  788.    }
  789.    memmove( s, block_buff, block_len );
  790.    un_copy_line( dest, window, TRUE );
  791.    return( rc );
  792. }
  793.  
  794.  
  795. /*
  796.  * Name:    block_fill
  797.  * Purpose: fill the block buffer with character
  798.  * Date:    June 5, 1991
  799.  * Passed:  block_buff:  local buffer for moves
  800.  *          fill_char:  fill character
  801.  *          block_len:  number of columns in block
  802.  * Notes:   Fill block_buffer for block_len characters using fill_char.  This
  803.  *          function is used only for BOX blocks.
  804.  */
  805. void block_fill( block_buff, fill_char, block_len)
  806. char *block_buff;
  807. int fill_char;
  808. int block_len;
  809. {
  810.    memset( block_buff, fill_char, block_len );
  811.    *(block_buff+block_len) = CONTROL_Z;
  812. }
  813.  
  814.  
  815. /*
  816.  * Name:    restore_start_end
  817.  * Purpose: a file has been modified - must restore all start and end pointers
  818.  * Date:    June 5, 1991
  819.  * Passed:  dest_file:  pointer to destination file structure
  820.  *          source_file:  pointer to source file structure
  821.  *          dest_mod:  net modifications in the destination file
  822.  *          source_mod:  net modifications in the source file
  823.  *          source_first:  we must know which file is stored first in memory
  824.  * Notes:   Go through the file list and adjust the start_text and end_text
  825.  *          file pointers as needed.   There are several cases that must be
  826.  *          be considered.  1) destination file and source file could be the
  827.  *          same.  2) if the file pointer we're looking at is below both
  828.  *          the source and destination, no action is needed.  3) the file
  829.  *          we're looking at could be between the source and destination.
  830.  *          4) the file we're looking at could be either source or destination.
  831.  *          5) the file we're looking at could be past both source and dest.
  832.  *          Use unsigned longs to compare pointers.
  833.  */
  834. void restore_start_end( dest_file, source_file, dest_mod, source_mod,
  835.                         source_first )
  836. file_infos *dest_file, *source_file;
  837. long dest_mod, source_mod;
  838. int source_first;
  839. {
  840. int same;
  841. long net_mod;
  842. unsigned long sst;      /* source start_text - keep these around for if's */
  843. unsigned long dst;      /* destination start_text */
  844. unsigned long ost;      /* open_file start_text */
  845. file_infos *open_file;
  846.  
  847.    net_mod = dest_mod + source_mod;
  848.    sst = ptoul( source_file->start_text );
  849.    dst = ptoul( dest_file->start_text );
  850.    same = (sst == dst) ? TRUE : FALSE;
  851.    for (open_file=g_status.file_list; open_file != NULL;
  852.              open_file=open_file->next) {
  853.       sst = ptoul( source_file->start_text );
  854.       dst = ptoul( dest_file->start_text );
  855.       ost = ptoul( open_file->start_text );
  856.       if (ost == sst) {
  857.          if (same)
  858.             source_file->end_text = addltop( net_mod, source_file->end_text);
  859.          else if (source_first)
  860.             source_file->end_text = addltop( source_mod,
  861.                                              source_file->end_text);
  862.          else {
  863.             source_file->start_text = addltop( dest_mod,
  864.                                              source_file->start_text);
  865.             source_file->end_text = addltop( net_mod, source_file->end_text);
  866.          }
  867.       } else if (ost == dst) {
  868.          if (source_first) {
  869.             dest_file->start_text = addltop( source_mod,
  870.                                              dest_file->start_text);
  871.             dest_file->end_text = addltop( net_mod, dest_file->end_text);
  872.          } else
  873.             dest_file->end_text = addltop( dest_mod, dest_file->end_text);
  874.       } else if (ost > sst) {
  875.          if (ost < dst) {
  876.             open_file->start_text = addltop( source_mod,
  877.                                              open_file->start_text);
  878.             open_file->end_text = addltop( source_mod, open_file->end_text);
  879.          } else {
  880.             open_file->start_text = addltop( net_mod, open_file->start_text);
  881.             open_file->end_text = addltop( net_mod, open_file->end_text);
  882.          }
  883.       } else if (ost > dst) {
  884.          if (ost < sst) {
  885.             open_file->start_text = addltop( dest_mod, open_file->start_text);
  886.             open_file->end_text = addltop( dest_mod, open_file->end_text);
  887.          } else {
  888.             open_file->start_text = addltop( net_mod, open_file->start_text);
  889.             open_file->end_text = addltop( net_mod, open_file->end_text);
  890.          }
  891.       }
  892.    }
  893. }
  894.  
  895.  
  896. /*
  897.  * Name:    restore_cursors
  898.  * Purpose: a file has been modified - must restore all cursor pointers
  899.  * Date:    June 5, 1991
  900.  * Passed:  dest_file:  target file for block actions
  901.  *          source_file:  source file for block actions
  902.  * Notes:   Go through the window list and adjust the cursor pointers
  903.  *          as needed.   This could be done by using the changes made by
  904.  *          the block actions, but it would be a real pain in the neck.
  905.  *          I chose to use the brute force approach.
  906.  */
  907. void restore_cursors( dest_file, source_file )
  908. file_infos *dest_file, *source_file;
  909. {
  910. windows *window;
  911. text_ptr p;
  912. file_infos *file;
  913. long beg_line, cur_line, test_line;
  914. unsigned long df, sf, f;
  915.  
  916.    df = ptoul( (text_ptr)dest_file );
  917.    sf = ptoul( (text_ptr)source_file );
  918.    window = g_status.window_list;
  919.    while (window != NULL) {
  920.       file = window->file_info;
  921.       f = ptoul( (text_ptr)file );
  922.       beg_line = 1;
  923.       cur_line = window->rline;
  924.       if (cur_line > file->length) {
  925.          file->end_text = cpb( file->end_text );
  926.          p = find_prev( file->end_text-1 );
  927.          if (p != NULL )
  928.             window->cursor = p;
  929.          else
  930.             window->cursor = file->start_text;
  931.          window->rline = file->length;
  932.          test_line = cur_line - file->length;
  933.          if (test_line < (long)(window->cline - (window->top_line - 1)))
  934.             window->cline -= test_line;
  935.       } else {
  936.          file->start_text = cpf( file->start_text );
  937.          for (p=file->start_text; p!=NULL && beg_line<cur_line; beg_line++)
  938.             p = find_next( p );
  939.          if (p != NULL )
  940.             window->cursor = p;
  941.          else {
  942.             window->cursor = file->start_text;
  943.             cur_line = file->length;
  944.          }
  945.          window->rline = cur_line;
  946.       }
  947.       if (window->rline < (window->cline - (window->top_line - 1)))
  948.          window->cline = window->rline + window->top_line - 1;
  949.       if ((f == df || f == sf) && window->visible )
  950.          show_size( window );
  951.       window = window->next;
  952.    }
  953. }
  954.  
  955.  
  956. /*
  957.  * Name:    delete_blocked_block
  958.  * Purpose: delete the marked text
  959.  * Date:    June 5, 1991
  960.  * Passed:  s_w:  source window
  961.  *          source:  pointer to line with block to delete
  962.  *          bc:  beginning column of block - BOX mode only
  963.  *          add:  number of characters in block to delete
  964.  *          prompt_line:  line to display error message if needed
  965.  * Notes:   Used only for BOX blocks.  Delete the block.  Delete any trailing
  966.  *          blanks at end of line.
  967.  */
  968. void delete_blocked_block( s_w, source, bc, add, prompt_line )
  969. windows *s_w;
  970. text_ptr source;
  971. int bc, add, prompt_line;
  972. {
  973. text_ptr s;
  974. text_ptr d;
  975. int number;
  976.  
  977.    number = linelen( source ) - bc + 2;
  978.    copy_line( source, prompt_line );
  979.    s = g_status.line_buff + bc + add;
  980.    d = s - add;
  981.    memmove( d, s, number );
  982.    un_copy_line( source, s_w, TRUE );
  983. }
  984.  
  985. /*
  986.  * Name:    check_block
  987.  * Purpose: To check that the block is still valid.
  988.  * Date:    June 5, 1991
  989.  * Notes:   After some editing, the marked block may not be valid.  For example,
  990.  *          deleting all the lines in a block in another window.
  991.  */
  992. void check_block( )
  993. {
  994. file_infos *file;
  995.  
  996.    file = g_status.marked_file;
  997.    if (file == NULL || file->block_br > file->length)
  998.       unmark_block( );
  999.    else {
  1000.       if (file->length < file->block_er)
  1001.          file->block_er = file->length;
  1002.       find_begblock( file );
  1003.       find_endblock( file );
  1004.    }
  1005. }
  1006.  
  1007.  
  1008. /*
  1009.  * Name:    find_begblock
  1010.  * Purpose: find the beginning line in file with marked block
  1011.  * Date:    June 5, 1991
  1012.  * Passed:  file: file containing marked block
  1013.  * Notes:   file->block_start contains starting line of marked block at end.
  1014.  */
  1015. void find_begblock( file )
  1016. file_infos *file;
  1017. {
  1018. text_ptr next;    /* start from beginning of file and go to end */
  1019. long i;           /* line counter */
  1020.  
  1021.    next = cpf( file->start_text );
  1022.    for (i=1; i<file->block_br && next != NULL; i++)
  1023.       next = find_next( next );
  1024.    if (next != NULL)
  1025.       file->block_start = next;
  1026. }
  1027.  
  1028.  
  1029. /*
  1030.  * Name:    find_endblock
  1031.  * Purpose: find the ending line in file with marked block
  1032.  * Date:    June 5, 1991
  1033.  * Passed:  file: file containing marked block
  1034.  * Notes:   If in LINE mode, file->block_end is set to end of line of last
  1035.  *          line in block.  If in BOX mode, file->block_end is set to
  1036.  *          beginning of last line in marked block.  If the search for the
  1037.  *          ending line of the marked block goes past the eof, set the
  1038.  *          ending line of the block to the last line in the file.
  1039.  */
  1040. void find_endblock( file )
  1041. file_infos *file;
  1042. {
  1043. text_ptr next;    /* start from beginning of file and go to end */
  1044. long i;           /* line counter */
  1045. int end_column;
  1046.  
  1047.    next = cpf( file->start_text );
  1048.    for (i=1; i<file->block_er && next != NULL; i++)
  1049.       next = find_next( next );
  1050.    if (next != NULL) {
  1051.       end_column = linelen( next );
  1052.       if (next[end_column] == '\n')
  1053.          ++end_column;
  1054.       if (file->block_type == LINE)
  1055.          file->block_end = next + end_column;
  1056.       else
  1057.          file->block_end = next;
  1058.    } else {
  1059.       file->end_text = cpb( file->end_text );
  1060.       if (file->block_type == LINE)
  1061.          file->block_end = file->end_text - 1;
  1062.       else {
  1063.          next = find_prev( file->end_text - 1 );
  1064.          if (next != NULL)
  1065.             file->block_end = next;
  1066.          else
  1067.             file->block_end = file->end_text - 1;
  1068.       }
  1069.       file->block_er = file->length;
  1070.    }
  1071. }
  1072.  
  1073. /*
  1074.  * Name:    block_write
  1075.  * Purpose: To write the currently marked block to a disk file.
  1076.  * Date:    June 5, 1991
  1077.  * Passed:  window: information required to access current window
  1078.  * Notes:   If the file already exists, the user gets to choose whether
  1079.  *           to overwrite or append.
  1080.  */
  1081. void block_write( window )
  1082. windows *window;
  1083. {
  1084. int prompt_line;
  1085. int rc;
  1086. char buff[MAX_COLS+2]; /* buffer for char and attribute  */
  1087. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1088. text_ptr block_start;   /* start of block in file */
  1089. text_ptr block_end;     /* end of block in file */
  1090. file_infos *file;
  1091. int block_type;
  1092.  
  1093.    /*
  1094.     * make sure block is marked OK
  1095.     */
  1096.    un_copy_line( window->cursor, window, TRUE );
  1097.    check_block( );
  1098.    if (g_status.marked == TRUE) {
  1099.       prompt_line = window->bottom_line;
  1100.       file        = window->file_info;
  1101.       block_start = file->block_start;
  1102.       block_end   = file->block_end;
  1103.       block_type  = file->block_type;
  1104.  
  1105.       /*
  1106.        * find out which file to write to
  1107.        */
  1108.       save_screen_line( 0, prompt_line, line_buff );
  1109.       if (get_name( "Filename: ", prompt_line, g_status.rw_name,
  1110.                     g_display.message_color ) == OK) {
  1111.          /*
  1112.           * if the file exists, find out whether to overwrite or append
  1113.           */
  1114.          if (hw_fattrib( g_status.rw_name ) != ERROR) {
  1115.             set_prompt( "File exists. Overwrite or Append? (o/a): ",
  1116.                          prompt_line );
  1117.             switch (get_oa( )) {
  1118.                case A_OVERWRITE :
  1119.                   hw_unlink( g_status.rw_name, prompt_line );
  1120.                   combine_strings( buff, "writing block to '",
  1121.                                    g_status.rw_name, "'" );
  1122.                   s_output( buff, prompt_line, 0, g_display.message_color );
  1123.                   rc = hw_save( g_status.rw_name, block_start, block_end,
  1124.                                 block_type, prompt_line );
  1125.                   if (rc == ERROR)
  1126.                      error( WARNING, prompt_line, "could not write block" );
  1127.                   break;
  1128.                case A_APPEND :
  1129.                   combine_strings( buff, "appending block to '",
  1130.                                    g_status.rw_name, "'" );
  1131.                   s_output( buff, prompt_line, 0, g_display.message_color );
  1132.                   rc = hw_append( g_status.rw_name, block_start, block_end,
  1133.                                   block_type, prompt_line );
  1134.                   if (rc == ERROR)
  1135.                      error( WARNING, prompt_line, "could not append block" );
  1136.                   break;
  1137.             }
  1138.          } else {
  1139.             combine_strings( buff, "writing block to '", g_status.rw_name,
  1140.                              "'" );
  1141.             s_output( buff, prompt_line, 0, g_display.message_color );
  1142.             if (hw_save( g_status.rw_name, block_start, block_end,
  1143.                          block_type, prompt_line ) == ERROR)
  1144.                error( WARNING, prompt_line, "could not write block" );
  1145.          }
  1146.       }
  1147.       restore_screen_line( 0, prompt_line, line_buff );
  1148.    }
  1149. }
  1150.  
  1151.  
  1152. /*
  1153.  * Name:    block_print
  1154.  * Purpose: Print an entire file or the currently marked block.
  1155.  * Date:    June 5, 1991
  1156.  * Passed:  window: information required to access current window
  1157.  */
  1158. void block_print( window )
  1159. windows *window;
  1160. {
  1161. char answer[MAX_COLS];  /* entire file or just marked block? */
  1162. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1163. int col, func;
  1164. int prompt_line;
  1165. text_ptr block_start;   /* start of block in file */
  1166. text_ptr block_end;     /* end of block in file */
  1167. file_infos *file;
  1168. int block_type;
  1169.  
  1170.    un_copy_line( window->cursor, window, TRUE );
  1171.    prompt_line = window->bottom_line;
  1172.    save_screen_line( 0, prompt_line, line_buff );
  1173.    /*
  1174.     * print entire file or just marked block?
  1175.     */
  1176.    strcpy( answer, "Print file or block? (f/b): " );
  1177.    col = strlen( answer );
  1178.    s_output( answer, prompt_line, 0, g_display.message_color );
  1179.    eol_clear( col, prompt_line, g_display.text_color );
  1180.    xygoto( col, prompt_line );
  1181.    func = col = 0;
  1182.    while (col != 'f' && col != 'F' && col != 'b' && col != 'B' && func != ESC) {
  1183.       col = getkey( );
  1184.       func = getfunc( col );
  1185.    }
  1186.    if (func != ESC) {
  1187.       file = window->file_info;
  1188.       if (col == 'f' || col == 'F') {
  1189.          strcpy( answer, "Printing file..." );
  1190.          block_start = file->start_text;
  1191.          block_end   = cpb( file->end_text ) - 1;
  1192.          block_type = NOTMARKED;
  1193.       } else if (col == 'b' || col == 'B') {
  1194.          check_block( );
  1195.          if (g_status.marked == TRUE) {
  1196.             strcpy( answer, "Printing block..." );
  1197.             block_start = file->block_start;
  1198.             block_end   = file->block_end;
  1199.             block_type = file->block_type;
  1200.          } else
  1201.             col = ESC;
  1202.       }
  1203.       if (col != ESC) {
  1204.          col = strlen( answer );
  1205.          s_output( answer, prompt_line, 0, g_display.message_color );
  1206.          eol_clear( col, prompt_line, g_display.text_color );
  1207.          if (hw_print( block_start, block_end, block_type, prompt_line ))
  1208.             error( WARNING, prompt_line, "error in printing text" );
  1209.       }
  1210.    }
  1211.    restore_screen_line( 0, prompt_line, line_buff );
  1212. }
  1213.  
  1214.  
  1215. /*
  1216.  * Name:    get_block_fill_char
  1217.  * Purpose: get the character to fill marked block.
  1218.  * Date:    June 5, 1991
  1219.  * Passed:  window: information required to access current window
  1220.  *          c: address of character to fill block
  1221.  */
  1222. int  get_block_fill_char( window, c )
  1223. windows *window;
  1224. int *c;
  1225. {
  1226. char answer[MAX_COLS];  /* entire file or just marked block? */
  1227. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1228. int col;
  1229. int prompt_line;
  1230. int rc;
  1231.  
  1232.    rc = OK;
  1233.    prompt_line = window->bottom_line;
  1234.    save_screen_line( 0, prompt_line, line_buff );
  1235.    strcpy( answer, "Enter character to fill block (ESC to exit): " );
  1236.    s_output( answer, prompt_line, 0, g_display.message_color );
  1237.    col = strlen( answer );
  1238.    eol_clear( col, prompt_line, g_display.text_color );
  1239.    xygoto( col, prompt_line );
  1240.    col = getkey( );
  1241.    if (col >= 256)
  1242.       rc = ERROR;
  1243.    else
  1244.       *c = col;
  1245.    restore_screen_line( 0, prompt_line, line_buff );
  1246.    return( rc );
  1247. }
  1248.  
  1249.  
  1250. /*
  1251.  * Name:    block_expand_tabs
  1252.  * Purpose: Expand tabs in a marked block.
  1253.  * Date:    June 5, 1991
  1254.  * Passed:  window:  pointer to current window
  1255.  * Notes:   Tabs are expanded using the current tab interval.
  1256.  *          Lines are checked to make sure they are not too long.
  1257.  */
  1258. void block_expand_tabs( window )
  1259. windows *window;
  1260. {
  1261. int prompt_line;
  1262. int len;
  1263. int tab;
  1264. int tab_size;
  1265. int dirty;
  1266. int spaces;
  1267. int net_change;
  1268. text_ptr p;                     /* pointer to block line */
  1269. file_infos *file;
  1270. windows s_w;
  1271. int block_type;
  1272. long er, li;
  1273. int bc, ec, tc;
  1274. int i, j;
  1275. char exp_buff[BUFF_SIZE+2], *b, *q, *s, *d, *lb;
  1276.  
  1277.    /*
  1278.     * make sure block is marked OK
  1279.     */
  1280.    un_copy_line( window->cursor, window, TRUE );
  1281.    check_block( );
  1282.    if (g_status.marked == TRUE) {
  1283.  
  1284.       /*
  1285.        * initialize everything
  1286.        */
  1287.       prompt_line = window->bottom_line;
  1288.       dirty = FALSE;
  1289.       tab_size = g_status.tab_size;
  1290.       file  = g_status.marked_file;
  1291.       bc = file->block_bc;
  1292.       ec = file->block_ec;
  1293.       p  = cpf( file->block_start );
  1294.       block_type = file->block_type;
  1295.       er = file->block_er;
  1296.       dup_window_info( &s_w, g_status.marked_window );
  1297.       lb = g_status.line_buff;
  1298.       for (s_w.rline = li = file->block_br; li<=er; li++, s_w.rline++) {
  1299.  
  1300.          /*
  1301.           * use the line buffer to expand LINE blocks.
  1302.           * use the line buffer and the exp buffer to expand BOX blocks.
  1303.           */
  1304.          tab = FALSE;
  1305.          len = linelen( p );
  1306.          net_change = 0;
  1307.          g_status.copied = FALSE;
  1308.          if (block_type == BOX) {
  1309.             if (len > bc) {
  1310.  
  1311.                /*
  1312.                 * copy the line starting at the beginning column of BOX to the
  1313.                 * line buffer.
  1314.                 */
  1315.                copy_line( p+bc, prompt_line);
  1316.                b = lb;
  1317.  
  1318.                /*
  1319.                 * put the characters in the BOX in the exp_buff.
  1320.                 */
  1321.                for (j=0,i=bc; i<= ec && i<len; i++,j++)
  1322.                   exp_buff[j] = *b++;
  1323.                exp_buff[j] = CONTROL_Z;
  1324.  
  1325.                /*
  1326.                 * now, delete all characters in BOX from line buffer.
  1327.                 */
  1328.                b = lb;
  1329.                i = (ec < len) ? ec+1 : len;
  1330.                i -= bc;
  1331.                s = b + i;
  1332.                j = linelen( s ) + 3;
  1333.                memmove( b, s, j );
  1334.  
  1335.                /*
  1336.                 * expand the tabs in the line buffer.
  1337.                 */
  1338.                b = exp_buff;
  1339.                for (b=exp_buff, i=bc+1; *b != CONTROL_Z; b++) {
  1340.                   if (*b == '\t') {
  1341.                      tab = TRUE;
  1342.                      spaces = i % tab_size;
  1343.                      if (spaces)
  1344.                         spaces = tab_size - spaces;
  1345.                      if (spaces) {
  1346.                         d = b + spaces;
  1347.                         j = linelen( b ) + 2;
  1348.                         memmove( d, b, j );
  1349.                      }
  1350.                      for (j=0; j<=spaces; j++)
  1351.                         *(b+j) =  ' ';
  1352.                      net_change += spaces;
  1353.                      i += spaces + 1;
  1354.                      b += spaces;
  1355.                   } else
  1356.                      i++;
  1357.                }
  1358.                if (tab == TRUE) {
  1359.  
  1360.                   /*
  1361.                    * make room in the line buffer for the expanded tabs.
  1362.                    */
  1363.                   i = linelen( exp_buff );
  1364.                   s = lb;
  1365.                   j = linelen( s ) + 2;
  1366.                   d = s + i;
  1367.                   memmove( d, s, j );
  1368.                   for (q=s, b=exp_buff; *b != CONTROL_Z;)
  1369.                      *q++ = *b++;
  1370.                   un_copy_line( p+bc, &s_w, TRUE );
  1371.                }
  1372.             }
  1373.          } else if (block_type == LINE) {
  1374.  
  1375.             /*
  1376.              * LINE blocks are easy.  copy the line into the line buffer (lb)
  1377.              * and expand the tabs if any.
  1378.              */
  1379.             copy_line( p, prompt_line);
  1380.             for (b=lb, i=1; *b != CONTROL_Z; b++) {
  1381.                if (*b == '\t') {
  1382.                   tab = TRUE;
  1383.                   spaces = i % tab_size;
  1384.                   if (spaces)
  1385.                      spaces = tab_size - spaces;
  1386.                   if (spaces) {
  1387.                      d = b + spaces;
  1388.                      j = linelen( b ) + 2;
  1389.                      memmove( d, b, j );
  1390.                   }
  1391.                   for (j=0; j<=spaces; j++)
  1392.                      *(b+j) =  ' ';
  1393.                   net_change += spaces;
  1394.                   i += spaces + 1;
  1395.                   b += spaces;
  1396.                } else
  1397.                   i++;
  1398.             }
  1399.             if (tab == TRUE)
  1400.                un_copy_line( p, &s_w, TRUE );
  1401.          }
  1402.          if (tab == TRUE)
  1403.             dirty = GLOBAL;
  1404.          p = find_next( p );
  1405.       }
  1406.  
  1407.       /*
  1408.        * IMPORTANT:  we need to reset the copied flag because the cursor may
  1409.        * not necessarily be on the last line of the block.
  1410.        */
  1411.       g_status.copied = FALSE;
  1412.       if (dirty) {
  1413.          check_block( );
  1414.          g_status.marked_file->dirty = dirty;
  1415.          show_avail_mem( );
  1416.       }
  1417.    }
  1418. }
  1419.